﻿using Microsoft.Extensions.Logging;
using Volo.Abp.Auditing;
using Volo.Abp.Domain;
using Volo.Abp.Domain.Entities;
using TianShu.Reposition;
using Volo.Abp.SqlSugarCore.Repositories;
using Volo.Abp.SqlSugarCore.Services;
using Volo.Abp.SqlSugarCore.SqlSugarFactory;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.MultiTenancy;
using Microsoft.Extensions.Options;
using Volo.Abp.Domain.Shared;
using Volo.Abp.Json;
using Volo.Abp;
using System.Collections.Concurrent;
using Volo.Abp.Domain.Shared;

namespace Volo.Abp.SqlSugarCore.Repositories
{
    public class SqlSugarCoreRepository<TEntity> : DalService<TEntity>, ISqlSugarCoreRepository<TEntity>
        where TEntity : class, IEntity, new()
    {
        public IJsonSerializer _jsonSerializer => LazyServiceProvider.LazyGetRequiredService<IJsonSerializer>();

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sqlSugarClientFactory"></param>
        /// <param name="httpContextAccessor"></param>
        public SqlSugarCoreRepository() : base()
        {

        }


        public async Task DeleteAsync([NotNull] Expression<Func<TEntity, bool>> predicate, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            var list = await GetListAsync(predicate);
            await DeleteManyAsync(list, autoSave, cancellationToken);
        }

        public async Task DeleteAsync([NotNull] TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await DeleteManyAsync(new List<TEntity> { entity }, autoSave, cancellationToken);
        }

        public async Task DeleteManyAsync([NotNull] IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            if (entities.Count() < 1)
            {
                return;
            }
            if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
            {
                foreach (var item in entities)
                {
                    ApplyAbpConceptsForDeletedEntity(item);
                }

                await Db.Updateable<TEntity>(entities).ExecuteCommandAsync();
                return;
            }

            await Db.Deleteable<TEntity>(entities).ExecuteCommandAsync();
        }

        public async Task<TEntity> FindAsync([NotNull] Expression<Func<TEntity, bool>> predicate, bool includeDetails = true,
            CancellationToken cancellationToken = default)
        {
            return await GetAll().FirstAsync(predicate);
        }


        public async Task<TEntity> GetAsync([NotNull] Expression<Func<TEntity, bool>> predicate, bool includeDetails = true,
            CancellationToken cancellationToken = default)
        {
            var entity = await FindAsync(predicate);
            if (entity == null)
            {
                throw new UserFriendlyException($"没有符合条件的数据");
            }

            return entity;
        }


        public async Task<long> GetCountAsync(Expression<Func<TEntity, bool>> expression = null, CancellationToken cancellationToken = default)
        {
            return await GetAll().CountAsync(expression);
        }

        public async Task<IEnumerable<TEntity>> GetListAsync([NotNull] Expression<Func<TEntity, bool>> predicate, bool includeDetails = false,
            CancellationToken cancellationToken = default)
        {
            return await GetAll().Where(predicate).ToListAsync();
        }

        public async Task<IEnumerable<TEntity>> GetListAsync([NotNull] Expression<Func<TEntity, bool>> predicate,
            Expression<Func<TEntity, object>> sortExpression, bool includeDetails = false, CancellationToken cancellationToken = default)
        {
            return await GetAll().Where(predicate).OrderBy(sortExpression).ToListAsync();
        }

        public async Task<(IEnumerable<TEntity>, long)> GetListAsync(List<UrlParams> urlParams, Expression<Func<TEntity, bool>> expression = null,
            CancellationToken cancellationToken = default)
        {
            List<string> list = EntityPropertyNames;
            IDictionary<string, object> pairs = null;
            //获取查询条件
            var condition = urlParams.GetCondition(list, ref pairs);

            var query = GetAll().Where(condition.ConditionalModels).OrderBy(condition.OrderCondition);
            if (expression != null)
            {
                query = query.Where(expression);
            }

            var result = await query.ToPageListAsync(condition.Page);
            return (result, condition.Page == null ? 0 : condition.Page.Count);
        }

        public async Task<IEnumerable<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string sorting,
            Expression<Func<TEntity, bool>> expression = null, bool includeDetails = false, CancellationToken cancellationToken = default)
        {
            var query = GetAll().OrderBy(sorting);
            var page = new PageDTO()
            {
                PageIndex = skipCount / maxResultCount,
                PageDataCount = maxResultCount,
            };
            var list = await query.ToPageListAsync(page);
            return list;
        }

        public async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await InsertManyAsync(new List<TEntity> { entity }, autoSave, cancellationToken);
            return entity;
        }

        public async Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            if (entities == null || entities.Count() < 1)
            {
                return;
            }

            foreach (var entity in entities)
            {
                TryToSetTenantId(entity);

                SetCreationAuditProperties(entity);

                TrySetGuidId(entity);
            }

            await Db.Insertable<TEntity>(entities).ExecuteCommandAsync();
        }

        public async Task<TEntity> UpdateAsync([NotNull] TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await UpdateManyAsync(new List<TEntity> { entity });
            return entity;
        }

        public async Task UpdateManyAsync([NotNull] IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            if (entities.Count()<1)
            {
                return;
            }
            foreach (var entity in entities)
            {
                SetModificationAuditProperties(entity);
            }

            List<string> ignoreColumnList = new List<string>();
            ignoreColumnList.Add(nameof(ICreationAuditedObject.CreationTime));
            ignoreColumnList.Add(nameof(ICreationAuditedObject.CreatorId));
            ignoreColumnList.Add(nameof(ICreationNameObject.CreationName));
            ignoreColumnList.Add(nameof(IDeletionAuditedObject.DeletionTime));
            ignoreColumnList.Add(nameof(IDeletionAuditedObject.DeleterId));
            ignoreColumnList.Add(nameof(IMultiTenant.TenantId));

            await Db.Updateable<TEntity>(entities).IgnoreColumns(ignoreColumnList.ToArray()).ExecuteCommandAsync();
        }



        public async Task<IDictionary<string, object>> GetDbDictionaryAsync(Expression<Func<TEntity, bool>> whereExpression,
            Expression<Func<TEntity, object>> keyExpression, Expression<Func<TEntity, object>> resultExpression)
        {
            return await GetAll().Where(whereExpression).ToDictionaryAsync(keyExpression, resultExpression);
        }

        public async Task<IDictionary<TKey, TResult>> GetDictionaryAsync<TKey, TResult>(Expression<Func<TEntity, bool>> whereExpression,
            Func<TEntity, TKey> keyExpression, Func<TEntity, TResult> resultExpression)
        {
            return (await GetAll().Where(whereExpression).ToListAsync()).ToDictionary(keyExpression, resultExpression);
        }

        public async Task<TResult> FindAsync<TResult>(Expression<Func<TEntity, bool>> whereExpression, Expression<Func<TEntity, TResult>> selectExpression,
            Expression<Func<TEntity, object>> sortExpression = null)
        {
            var query = GetAll().Where(whereExpression);
            if (sortExpression != null)
            {
                query = query.OrderBy(sortExpression);
            }

            return await query.Select(selectExpression).FirstAsync();
        }

        public Guid TrySetGuidId(TEntity entity)
        {
            return base.TrySetGuidId(entity);
        }

        /// <summary>
        /// 获取sqlsugar查询
        /// </summary>
        /// <returns></returns>
        public async Task<ISugarQueryable<TEntity>> GetQueryableAsync()
        {
            return await Task.FromResult(GetAll<TEntity>());
        }
    }


    public class SqlSugarCoreRepository<TEntity, TKey> : SqlSugarCoreRepository<TEntity>,
        ISqlSugarCoreRepository<TEntity, TKey>
        where TEntity : class, IEntity<TKey>, new()
    {
        public SqlSugarCoreRepository() : base()
        {
        }

        public async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            await DeleteAsync(e => SqlFunc.Equals(e.Id, id));
        }

        public async Task DeleteManyAsync([NotNull] IEnumerable<TKey> ids, bool autoSave = false, CancellationToken cancellationToken = default)
        {
            if (ids.Count()<1)
            {
                return;
            }
            await DeleteAsync(e => SqlFunc.ContainsArray(ids.ToArray(), e.Id));
        }

        public async Task<TEntity> GetAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            var entity = await GetAsync(e => e.Id.Equals(id));
            return entity;
        }

        public async Task<TEntity> FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default)
        {
            var entity = await FindAsync(e => SqlFunc.Equals(id, e.Id));
            return entity;
        }
    }
}